#include "CTgdb.h"
#ifdef __cplusplus
extern "C"
{
#endif
#include "tgdb_client_interface.h"
#include "fs_util.h"
#include "ibuf.h"
#include "io.h"
#include "queue.h"
#include "pseudo.h"		/* SLAVE_SIZE constant */
#include "fork_util.h"
#include "sys_util.h"
#include "tgdb_list.h"
#include "logger.h"
#ifdef __cplusplus
}
#endif
static void tgdb_request_destroy (void *item)
{
	tgdb_request_ptr request_ptr = (tgdb_request_ptr) item;
	switch (request_ptr->header) 
	{
		case TGDB_REQUEST_CONSOLE_COMMAND:
			free ((char*)request_ptr->choice.console_command.command);
			request_ptr->choice.console_command.command = NULL;
			break;
		case TGDB_REQUEST_INFO_SOURCES:
			break;
		case TGDB_REQUEST_FILENAME_PAIR:
			free ((char*)request_ptr->choice.filename_pair.file);
			request_ptr->choice.filename_pair.file = NULL;
			break;
		case TGDB_REQUEST_DEBUGGER_COMMAND:
			break;
		case TGDB_REQUEST_MODIFY_BREAKPOINT:
			free ((char*)request_ptr->choice.modify_breakpoint.file);
			request_ptr->choice.modify_breakpoint.file = NULL;
			break;
		case TGDB_REQUEST_COMPLETE:
			free ((char*)request_ptr->choice.complete.line);
			request_ptr->choice.complete.line = NULL;
			break;
		default:
			break;
	}
	free (request_ptr);
	request_ptr = NULL;
}


Ctgdb::Ctgdb()
{
	tcc = NULL;
	control_c = 0;
	isInitiolized = false;
	debugger_stdout = -1;
	debugger_stdin = -1;

	inferior_stdout = -1;
	inferior_stdin = 0;

	gdb_client_request_queue = NULL;
	gdb_input_queue = NULL;
	oob_input_queue = NULL;

	IS_SUBSYSTEM_READY_FOR_NEXT_COMMAND = 1;

	last_gui_command = NULL;
	show_gui_commands = 0;

	m_target = NULL;

	command_list = tgdb_list_init ();
	has_sigchld_recv = 0;

	num_loggers = 0;
	m_logger = NULL;
}



/*******************************************************************************
 * This is the basic initialization
 ******************************************************************************/

/* 
 * Gets the users home dir and creates the config directory.
 *
 * \param tgdb
 * The tgdb context.
 *
 * \param config_dir 
 * Should be FSUTIL_PATH_MAX in size on way in.
 * On way out, it will be the path to the config dir
 *
 * \return
 * -1 on error, or 0 on success
 */
int Ctgdb::Initialize_config_dir (char *config_dir)
{
	/* Get the home directory */
	char *home_dir = getenv ("HOME");
	const char *tgdb_dir = ".tgdb";

	/* Create the config directory */
	if (!fs_util_create_dir_in_base (home_dir, tgdb_dir))
	{
		Logger_write_pos( __FILE__, __LINE__,
				"fs_util_create_dir_in_base error");
		return -1;
	}

	fs_util_get_path (home_dir, tgdb_dir, config_dir);

	return 0;
}

/**
 * Knowing the user's home directory, TGDB can initialize the m_logger interface
 *
 * \param tgdb
 * The tgdb context.
 *
 * \param config_dir 
 * The path to the user's config directory
 *
 * \return
 * -1 on error, or 0 on success
 */
int Ctgdb::Initialize_logger_interface(char *config_dir)
{

	/* Get the home directory */
	const char *tgdb_log_file = "tgdb_log.txt";
	char tgdb_log_path[FSUTIL_PATH_MAX];

	fs_util_get_path (config_dir, tgdb_log_file, tgdb_log_path);

	/* Initialize the logger */
	if (num_loggers == 0)
	{
		m_logger = logger_create ();

		if (!m_logger)
		{
			printf ("Error: Could not create log file\n");
			return -1;
		}
	}

	++num_loggers;

	if (logger_set_file (m_logger, tgdb_log_path) == -1)
	{
		printf ("Error: Could not open log file\n");
		return -1;
	}

	return 0;
}

/* Createing and Destroying a libtgdb context. {{{*/

/**
 * This initializes a tgdb library instance. It starts up the debugger and 
 * returns all file descriptors the client must select on.
 *
 * The client must call this function before any other function in the 
 * tgdb library.
 *
 * \param debugger
 * The path to the desired debugger to use. If this is NULL, then just
 * "gdb" is used.
 *
 * \param argc
 * The number of arguments to pass to the debugger
 *
 * \param argv
 * The arguments to pass to the debugger    
 *
 * \param debugger_fd
 * The descriptor to the debugger's I/O
 *
 * \param inferior_fd
 * The descriptor to the I/O of the program being debugged.
 *
 * @return
 * NULL if OK
 */
int Ctgdb::Initialize (const char *debugger,
		int argc, char **argv,
		int *debugger_fd, int *inferior_fd)
{
	char config_dir[FSUTIL_PATH_MAX];


	/* Create config directory */
	if (Initialize_config_dir (config_dir) == -1)
	{
		Logger_write_pos( __FILE__, __LINE__, "tgdb_initialize error");
		return -1;
	}
	
	if (Initialize_logger_interface (config_dir) == -1)
	{
		printf ("Could not initialize logger interface\n");
		return -1;
	}

	gdb_client_request_queue  = queue_init ();
	gdb_input_queue		  = queue_init ();
	oob_input_queue		  = queue_init ();

	tcc = tgdb_client_create_context (debugger, argc, argv, config_dir,
			TGDB_CLIENT_DEBUGGER_GNU_GDB,
			TGDB_CLIENT_PROTOCOL_GNU_GDB_ANNOTATE_TWO,
			m_logger);

	/* create an instance and initialize a tgdb_client_context */
	if (tcc == NULL)
	{
		Logger_write_pos( __FILE__, __LINE__,
				"tgdb_client_create_context failed");
		return -1;
	}

	if (tgdb_client_initialize_context (tcc,
				&(debugger_stdin),
				&(debugger_stdout),
				&(inferior_stdin),
				&(inferior_stdout)) == -1)
	{
		Logger_write_pos( __FILE__, __LINE__,
				"tgdb_client_initialize failed");
		return -1;
	}

	Process_client_commands();

	*debugger_fd = debugger_stdout;
	*inferior_fd = inferior_stdout;
	isInitiolized = true;
	return 0;
}

int Ctgdb::Logger_write_pos( const char *file,  int line, const char *fmt, ...)
{
	va_list ap;
	char va_buf[MAXLINE];

	if ( !m_logger )
		return -1;

	/* It's OK to write nothing */
	if ( !fmt )
		return 0;

	/* Get the buffer with format */
	va_start(ap, fmt);
#ifdef   HAVE_VSNPRINTF
	vsnprintf(va_buf, sizeof(va_buf), fmt, ap);  /* this is safe */
#else
	vsprintf(va_buf, fmt, ap);             /* this is not safe */
#endif
	va_end(ap);

	return logger_write_pos(m_logger, file, line, va_buf);
}


bool Ctgdb::IsInitiolized()
{return isInitiolized;}

/**
 * This will terminate a libtgdb session. No functions should be called on
 * the tgdb context passed into this function after this call.
 *
 * \param tgdb
 * An instance of the tgdb library to operate on.
 *
 * @return
 * 0 on success or -1 on error
 */
int Ctgdb::Shutdown()
{
	/* Free the logger */
	if (num_loggers == 1)
	{
		if (logger_destroy (m_logger) == -1)
		{
			printf ("Could not destroy logger interface\n");
			return -1;
		}
	}

	--num_loggers;
	isInitiolized = false;
	return tgdb_client_destroy_context(tcc);
}


/* Status Commands {{{*/
/******************************************************************************/
/**
 * @name Status Commands
 * These functions are for querying the tgdb context.
 */
/******************************************************************************/

/*@{*/

/**
 * If a function returns an error, this can be called to report more
 * about the type of error, or the error message itself.
 *
 * \param tgdb
 * An instance of the tgdb library to operate on.
 *
 * @return
 * Error Message or NULL on error
 */
char* Ctgdb::GetErrorMsg()
{
	return NULL;
}

char * Ctgdb::Get_client_command(enum tgdb_command_type c)
{
	return tgdb_client_return_command(tcc, c);
}


char * Ctgdb::Client_modify_breakpoint_call (const char *file,
		int line, enum tgdb_breakpoint_action b)
{
	return tgdb_client_modify_breakpoint (tcc, file, line, b);
}


/* These functions are used to determine the state of libtgdb */

/**
 * Determines if tgdb should send data to gdb or put it in a buffer. This 
 * is when the debugger is ready and there are no commands to run.
 *
 * \return
 * true if can issue directly to gdb. Otherwise false.
 */
bool Ctgdb::Can_issue_command()
{
	if (IS_SUBSYSTEM_READY_FOR_NEXT_COMMAND &&
			tgdb_client_is_client_ready (tcc) &&
			(queue_size (gdb_input_queue) == 0))
		return true;

	return false;
}


/**
 * Determines if tgdb has commands it needs to run.
 *
 * \return
 * true if can issue directly to gdb. Otherwise false.
 */
bool Ctgdb::Has_command_to_run()
{
	if (tgdb_client_is_client_ready (tcc) && 
			((queue_size (gdb_input_queue) > 0) ||
			 (queue_size (oob_input_queue) > 0)))
		return true;

	return false;
}

/**
 * This will check to see if TGDB is currently capable of receiving another command.
 * 
 * \param tgdb
 * An instance of the tgdb library to operate on.
 *
 * \param is_busy
 * Will return as 1 if tgdb is busy, otherwise 0.
 *
 * \return
 * 0 on success, or -1 on error
 */
int Ctgdb::IsBusy (int *is_busy)
{
	/* Validate parameters */
	if (!is_busy)
	{
		Logger_write_pos( __FILE__, __LINE__, "tgdb_is_busy failed");
		return -1;
	}

	if (Can_issue_command())
		*is_busy = 0;
	else
		*is_busy = 1;

	return 0;
}





void Ctgdb::Handle_signals()
{
	if (control_c)
	{
		queue_free_list (gdb_input_queue, tgdb_command_destroy);
		queue_free_list (gdb_client_request_queue, tgdb_request_destroy);
		control_c = 0;
	}
}
/**
 * This function does most of the dirty work in TGDB. It is capable of 
 * processing the output of the debugger, to either satisfy a previously 
 * made request, or to simply get console output for the caller to have.
 *
 * The data returned from this function is the console output of the 
 * debugger.
 * 
 * \param tgdb
 * An instance of the tgdb library to operate on.
 *
 * \param buf
 * The output of the debugger will be returned in this buffer.
 * The buffer passed back will not exceed N in size.
 *
 * \param n
 * Tells libtgdb how large the buffer BUF is that the client passed in.
 *
 * \param is_finished
 * If this is passed in as NULL, it is not set.
 *
 * If it is non-null, it will be set to 1 if TGDB finished processing the
 * current request. Otherwise, it will be set to 0 if TGDB needs more input
 * in order to finish processing the current requested command.
 *
 * @return
 * The number of valid bytes in BUF on success, or -1 on error.
 */
size_t Ctgdb::Process(char *buf, size_t n, int *is_finished, ITarget** target)
{

	char local_buf[10 * n];
	ssize_t size;
	size_t buf_size = 0;
	int is_busy;

	/* make the queue empty */
	Delete_responses();
	*target = m_target;
	/* TODO: This is kind of a hack.
	 * Since I know that I didn't do a read yet, the next select loop will
	 * get me back here. This probably shouldn't return, however, I have to
	 * re-write a lot of this function. Also, I think this function should
	 * return a malloc'd string, not a static buffer.
	 *
	 * Currently, I see it as a bigger hack to try to just append this to the
	 * beggining of buf.
	 */
	if (last_gui_command != NULL)
	{
		int ret;

		if (IsBusy( &is_busy) == -1)
		{
			Logger_write_pos( __FILE__, __LINE__, 
					"tgdb_is_busy failed");
			return -1;
		}
		*is_finished = !is_busy;

		if (show_gui_commands)
		{
			strcpy (buf, last_gui_command);
			ret = strlen (last_gui_command);
		}
		else
		{
			strcpy (buf, "\n");
			ret = 1;
		}

		free (last_gui_command);
		last_gui_command = NULL;
		return ret;
	}

	if (has_sigchld_recv)
	{
		int tgdb_will_quit;
		/* tgdb_get_quit_command will return right away, it's asynchrounous.
		 * We call it to determine if it was GDB that died.
		 * If GDB didn't die, things will work like normal. ignore this.
		 * If GDB did die, this get's the quit command and add's it to the list. It's
		 * OK that the rest of this function get's executed, since the read will simply
		 * return EOF.
		 */
		int val = Get_quit_command(&tgdb_will_quit);
		if (val == -1)
		{
			Logger_write_pos( __FILE__, __LINE__,
					"tgdb_get_quit_command error");
			return -1;
		}
		has_sigchld_recv = 0;
		if (tgdb_will_quit)
			goto tgdb_finish;
	}

	/* set buf to null for debug reasons */
	memset (buf, '\0', n);

	/* 1. read all the data possible from gdb that is ready. */
	if ((size = io_read (debugger_stdout, local_buf, n)) < 0)
	{
		Logger_write_pos( __FILE__, __LINE__,
				"could not read from masterfd");
		buf_size = -1;
		Add_quit_command();
		goto tgdb_finish;
	}
	else if (size == 0)
	{				/* EOF */
		Add_quit_command();
		goto tgdb_finish;
	}

	local_buf[size] = '\0';

	/* 2. At this point local_buf has everything new from this read.
	 * Basically this function is responsible for seperating the annotations
	 * that gdb writes from the data. 
	 *
	 * buf and buf_size are the data to be returned from the user.
	 */
	{
		/* unused for now */
		char *infbuf = NULL;
		size_t infbuf_size;
		int result;
		result = tgdb_client_parse_io (tcc,
				local_buf, size,
				buf, &buf_size,
				infbuf, &infbuf_size, command_list);

		Process_client_commands();

		if (result == 0)
		{
			/* success, and more to parse, ss isn't done */
		}
		else if (result == 1)
		{
			/* success, and finished command */
			IS_SUBSYSTEM_READY_FOR_NEXT_COMMAND = 1;	
		}
		else if (result == -1)
		{
			Logger_write_pos( __FILE__, __LINE__,
					"tgdb_client_parse_io failed");
		}
	}

	/* 3. if ^c has been sent, clear the buffers.
	 *        If a signal has been recieved, clear the queue and return
	 */
	Handle_signals();
	
	/* 4. runs the users buffered command if any exists */
	if (Has_command_to_run ())
		Unqueue_and_deliver_command();

tgdb_finish:

	/* Set the iterator to the beggining. So when the user
	 * calls tgdb_get_command it, it will be in the right spot.
	 */
	command_list_iterator = tgdb_list_get_first(command_list);

	if (IsBusy (&is_busy) == -1)
	{
		Logger_write_pos( __FILE__, __LINE__, "tgdb_is_busy failed");
		return -1;
	}
	*is_finished = !is_busy;

	return buf_size;
}


int Ctgdb::Process_console_command(tgdb_request_ptr request)
{
	struct ibuf *command;

	if (!request)
		return -1;

	if (!Can_issue_command())
		return -1;

	if (request->header != TGDB_REQUEST_CONSOLE_COMMAND)
		return -1;

	command = ibuf_init ();
	ibuf_add (command, request->choice.console_command.command);
	ibuf_addchar (command, '\n');

	if (Send(ibuf_get (command), TGDB_COMMAND_CONSOLE) == -1)
	{
		Logger_write_pos( __FILE__, __LINE__, "tgdb_send failed");
		return -1;
	}

	ibuf_free (command);
	command = NULL;

	return 0;
}

int Ctgdb::Process_info_sources(tgdb_request_ptr request)
{
	int ret;

	if (!request)
		return -1;

	if (request->header != TGDB_REQUEST_INFO_SOURCES)
		return -1;

	ret = tgdb_client_get_inferior_source_files(tcc);
	Process_client_commands();

	return ret;
}

int Ctgdb::Process_filename_pair (tgdb_request_ptr request)
{
	int ret;

	if (!request)
		return -1;

	if (request->header != TGDB_REQUEST_FILENAME_PAIR)
		return -1;

	ret = tgdb_client_get_filename_pair (tcc, request->choice.filename_pair.file);
	Process_client_commands();

	return ret;
}


int Ctgdb::Process_current_location(tgdb_request_ptr request)
{
	int ret = 0;

	if (!request)
		return -1;

	if (request->header != TGDB_REQUEST_CURRENT_LOCATION)
		return -1;

	ret = tgdb_client_get_current_location (tcc, request->choice.current_location.on_startup);
	Process_client_commands();

	return ret;
}

int Ctgdb::Process_debugger_command(tgdb_request_ptr request)
{
	char command[255];
	if (!request)
		return -1;

	if (request->header != TGDB_REQUEST_DEBUGGER_COMMAND)
		return -1;

	sprintf(command,  Get_client_command(request->choice.debugger_command.c));
	return Send(command, TGDB_COMMAND_FRONT_END);
}

int Ctgdb::Process_modify_breakpoint (tgdb_request_ptr request)
{
	char *val;

	if (!request)
		return -1;

	if (request->header != TGDB_REQUEST_MODIFY_BREAKPOINT)
		return -1;

	val = Client_modify_breakpoint_call (
			request->choice.modify_breakpoint.file, 
			request->choice.modify_breakpoint.line, 
			request->choice.modify_breakpoint.b);

	if (val == NULL)
		return -1;

	if (Send(val, TGDB_COMMAND_FRONT_END) == -1)
	{
		Logger_write_pos( __FILE__, __LINE__, "tgdb_send failed");
		return -1;
	}

	free (val);

	return 0;
}

int Ctgdb::Process_complete(tgdb_request_ptr request)
{
	int ret;

	if (!request)
		return -1;

	if (request->header != TGDB_REQUEST_COMPLETE)
		return -1;

	ret = tgdb_client_completion_callback(tcc, request->choice.complete.line);
	Process_client_commands();

	return ret;
}

/* Input/Output commands {{{*/
/******************************************************************************/
/**
 * @name Input/Output commands
 * These functions are for communicating I/O with the tgdb context.
 */
/******************************************************************************/

/*@{*/

/**
 * Have TGDB process a command.
 * 
 * \param tgdb
 * An instance of the tgdb library to operate on.
 * 
 * \param request
 * The requested command to have TGDB process.
 *
 * \return
 * 0 on success or -1 on error
 */
int Ctgdb::ProcessCommand(tgdb_request_ptr request, char* param)
{

	if (!request)
		return -1;

	if (Can_issue_command())
		return -1;

	if (request->header == TGDB_REQUEST_CONSOLE_COMMAND)
		return Process_console_command (request);
	else if (request->header == TGDB_REQUEST_INFO_SOURCES)
		return Process_info_sources (request);
	else if (request->header == TGDB_REQUEST_FILENAME_PAIR)
		return Process_filename_pair (request);
	else if (request->header == TGDB_REQUEST_CURRENT_LOCATION)
		return Process_current_location (request);
	else if (request->header == TGDB_REQUEST_DEBUGGER_COMMAND)
		return Process_debugger_command(request);
	else if (request->header == TGDB_REQUEST_MODIFY_BREAKPOINT)
		return Process_modify_breakpoint (request);
	else if (request->header == TGDB_REQUEST_COMPLETE)
		return Process_complete (request);

	return 0;
}

int Ctgdb::ProcessCommand(tgdb_request_ptr request)
{
	return ProcessCommand(request, NULL);
}

int Ctgdb::ProcessCustomeRequest(ICustomeRequest* request)
{
	if (!request)
		return -1;
	return Send(request->GetCommand(), TGDB_COMMAND_FRONT_END, request->GetTarget());
}
/**
 * Process the commands that were created by the client
 *
 * \param tgdb
 * The TGDB context
 *
 * \return
 * -1 on error, 0 on success
 */
int Ctgdb::Process_client_commands()
{
	struct tgdb_list *client_command_list;
	tgdb_list_iterator *iterator;
	struct tgdb_command *command;

	client_command_list = tgdb_client_get_client_commands (tcc);
	iterator = tgdb_list_get_first (client_command_list);

	while (iterator)
	{
		command = (struct tgdb_command *) tgdb_list_get_item (iterator);

		if (Run_or_queue_command(command) == -1)
		{
			Logger_write_pos( __FILE__, __LINE__,
					"Run_or_queue_command failed");
			return -1;
		}

		iterator = tgdb_list_next (iterator);
	}

	/* free the list of client commands */
	tgdb_list_clear (client_command_list);

	return 0;
}
/*******************************************************************************
 * This is the main_loop stuff for tgdb-base
 ******************************************************************************/

/* 
 * Sends a command to the debugger. This function gets called when the GUI
 * wants to run a command.
 *
 * \param tgdb
 * An instance of the tgdb library to operate on.
 *
 * \param command
 * This is the command that should be sent to the debugger.
 *
 * \param command_choice
 * This tells tgdb_send who is sending the command.
 *
 * \return
 * 0 on success, or -1 on error.
 */

int Ctgdb::Send(char *command, enum tgdb_command_choice command_choice, ITarget* target)
{
	struct tgdb_command *tc;
	struct ibuf *temp_command = ibuf_init ();
	int length = strlen (command);

	/* Add a newline to the end of the command if it doesn't exist */
	ibuf_add (temp_command, command);

	if (command[length - 1] != '\n')
		ibuf_addchar (temp_command, '\n');

	/* Create the client command */
	tc = tgdb_command_create (ibuf_get (temp_command), command_choice, NULL);
	tc->ITarget = (void*) target;

	ibuf_free (temp_command);
	temp_command = NULL;

	if (Run_or_queue_command(tc) == -1)
	{
		Logger_write_pos( __FILE__, __LINE__,
				"tgdb_run_or_queue_command failed");
		return -1;
	}

	if (tgdb_client_tgdb_ran_command(tcc) == -1)
	{
		Logger_write_pos( __FILE__, __LINE__,
				"tgdb_client_tgdb_ran_command failed");
		return -1;
	}

	Process_client_commands();

	return 0;
}


int Ctgdb::Send(char *command, enum tgdb_command_choice command_choice)
{
	return Send(command, command_choice, NULL);
}
/**
 * If TGDB is ready to process another command, then this command will be
 * sent to the debugger. However, if TGDB is not ready to process another command,
 * then the command will be queued and run when TGDB is ready.
 *
 * \param tgdb
 * The TGDB context to use.
 *
 * \param command
 * The command to run or queue.
 *
 * \return
 * 0 on success or -1 on error
 */
int Ctgdb::Run_or_queue_command (struct tgdb_command *command)
{
	bool can_issue;

	can_issue = Can_issue_command();

	if (can_issue)
	{
		if (Deliver_command(command) == -1)
			return -1;
	} else {
		/* Make sure to put the command into the correct queue. */
		switch (command->command_choice)
		{
			case TGDB_COMMAND_FRONT_END:
			case TGDB_COMMAND_TGDB_CLIENT:
			case TGDB_CUSTOME_COMMAND_FRONT_END:
				queue_append (gdb_input_queue, command);
				break;
			case TGDB_COMMAND_TGDB_CLIENT_PRIORITY:
				queue_append (oob_input_queue, command);
				break;
			case TGDB_COMMAND_CONSOLE:
				Logger_write_pos( __FILE__, __LINE__, "unimplemented command");
				return -1;
				break;
			default:
				Logger_write_pos( __FILE__, __LINE__, "unimplemented command");
				return -1;
		}
	}

	return 0;
}
/** 
 * Will send a command to the debugger immediatly. No queueing will be done
 * at this point.
 *
 * \param tgdb
 * The TGDB context to use.
 *
 * \param command 
 * The command to run.
 *
 *  NOTE: This function assummes valid commands are being sent to it. 
 *        Error checking should be done before inserting into queue.
 */
int Ctgdb::Deliver_command(struct tgdb_command *command)
{
	IS_SUBSYSTEM_READY_FOR_NEXT_COMMAND = 0;

	/* Here is where the command is actually given to the debugger.
	 * Before this is done, if the command is a GUI command, we save it,
	 * so that later, it can be printed to the client. Its for debugging
	 * purposes only, or for people who want to know the commands there
	 * debugger is being given.
	 */
	if (command->command_choice == TGDB_CUSTOME_COMMAND_FRONT_END)
	{
		last_gui_command = cgdb_strdup (command->tgdb_command_data);
		m_target = (ITarget*) command->target;
	}
	else
	{
		m_target = NULL; 
	}

	/* A command for the debugger */
	if (tgdb_client_prepare_for_command (tcc, command) == -1)
		return -1;

	/* A regular command from the client */
	io_debug_write_fmt ("<%s>", command->tgdb_command_data);

	io_writen (debugger_stdin, command->tgdb_command_data,
			strlen (command->tgdb_command_data));

	/* Uncomment this if you wish to see all of the commands, that are 
	 * passed to GDB. */
#if 0
	{
		char *s = strdup (client_command->tgdb_client_command_data);
		int length = strlen (s);
		s[length - 1] = '\0';
		fprintf (stderr, "[%s]\n", s);
		s[length - 1] = ' ';
		free (s);
		s = NULL;
	}
#endif

	return 0;
}

/**
 * TGDB will search it's command queue's and determine what the next command
 * to deliever to GDB should be.
 *
 * \return
 * 0 on success, -1 on error
 */
int Ctgdb::Unqueue_and_deliver_command()
{
tgdb_unqueue_and_deliver_command_tag:

	/* This will redisplay the prompt when a command is run
	 * through the gui with data on the console.
	 */
	/* The out of band commands should always be run first */
	if (queue_size (oob_input_queue) > 0)
	{
		/* These commands are always run. 
		 * However, if an assumption is made that a misc
		 * prompt can never be set while in this spot.
		 */
		tgdb_command *item = NULL;
		item = (tgdb_command *) queue_pop(oob_input_queue);
		Deliver_command (item);
		tgdb_command_destroy (item);
	}
	/* If the queue is not empty, run a command */
	else if (queue_size (gdb_input_queue) > 0)
	{
		struct tgdb_command *item = NULL;
		item = (tgdb_command *) queue_pop (gdb_input_queue);

		/* If at the misc prompt, don't run the internal tgdb commands,
		 * In fact throw them out for now, since they are only 
		 * 'info breakpoints' */
		if (tgdb_client_can_tgdb_run_commands (tcc) == 1)
		{
			if (item->command_choice != TGDB_COMMAND_CONSOLE)
			{
				tgdb_command_destroy (item);
				goto tgdb_unqueue_and_deliver_command_tag;
			}
		}

		/* This happens when a command was skipped because the client no longer
		 * needs the command to be run */
		if (Deliver_command(item) == -1)
			goto tgdb_unqueue_and_deliver_command_tag;

		tgdb_command_destroy (item);
	}

	return 0;
}

/**
 * This sends a byte of data to the program being debugged.
 *
 * \param tgdb
 * An instance of the tgdb library to operate on.
 *
 * \param c
 * The character to pass to the program being debugged.
 *
 * @return
 * 0 on success or -1 on error
 */
int Ctgdb::Send_inferior_char(char c)
{
	if (io_write_byte (inferior_stdout, c) == -1)
	{
		Logger_write_pos( __FILE__, __LINE__, "io_write_byte failed");
		return -1;
	}

	return 0;
}


/**
 * Gets the ouput from the program being debugged.
 * 
 * \param tgdb
 * An instance of the tgdb library to operate on.
 *
 * \param buf
 * The output of the program being debugged will be returned here.
 *
 * \param n
 * Tells libtgdb how large the buffer BUF is.
 *
 * @return
 * The number of valid bytes in BUF on success, or 0 on error.
 */
size_t Ctgdb::Recv_inferior_data (char *buf, size_t n)
{
	char local_buf[n + 1];
	ssize_t size;

	/* read all the data possible from the child that is ready. */
	if ((size = io_read (inferior_stdin, local_buf, n)) < 0)
	{
		Logger_write_pos( __FILE__, __LINE__,
				"inferior_fd read failed");
		return -1;
	}

	strncpy (buf, local_buf, size);
	buf[size] = '\0';

	return size;
}

/**
 * TGDB is going to quit.
 *
 * \param tgdb
 * The tgdb context
 *
 * \return
 * 0 on success or -1 on error
 */
int Ctgdb::Add_quit_command()
{
	struct tgdb_debugger_exit_status *tstatus;
	struct tgdb_response *response; 

	tstatus = (struct tgdb_debugger_exit_status *)
		cgdb_malloc (sizeof (struct tgdb_debugger_exit_status));

	/* Child did not exit normally */
	tstatus->exit_status = -1;
	tstatus->return_value = 0;

	response = (struct tgdb_response *) cgdb_malloc (sizeof (struct tgdb_response));
	response->header = TGDB_QUIT;
	response->choice.quit.exit_status = tstatus;

	tgdb_types_append_command (command_list, response);

	return 0;
}

/**
 * This is called when GDB has finished.
 * Its job is to add the type of QUIT command that is appropriate.
 *
 * \param tgdb
 * The tgdb context
 *
 * \param tgdb_will_quit
 * This will return as 1 if tgdb sent the TGDB_QUIT command. Otherwise 0.
 * 
 * \return
 * 0 on success or -1 on error
 */
int Ctgdb::Get_quit_command (int *tgdb_will_quit)
{
	pid_t pid = tgdb_client_get_debugger_pid (tcc);
	int status = 0;
	pid_t ret;
	struct tgdb_debugger_exit_status *tstatus;
	struct tgdb_response *response = (struct tgdb_response *)
		cgdb_malloc (sizeof (struct tgdb_response));

	if (!tgdb_will_quit)
		return -1;

	*tgdb_will_quit = 0;

	tstatus = (struct tgdb_debugger_exit_status *)
		cgdb_malloc (sizeof (struct tgdb_debugger_exit_status));

	ret = waitpid (pid, &status, WNOHANG);

	if (ret == -1)
	{
		Logger_write_pos( __FILE__, __LINE__, "waitpid error");
		return -1;
	}
	else if (ret == 0)
	{
		/* This SIGCHLD wasn't for GDB */
		return 0;
	}

	if ((WIFEXITED (status)) == 0)
	{
		/* Child did not exit normally */
		tstatus->exit_status = -1;
		tstatus->return_value = 0;
	}
	else
	{
		tstatus->exit_status = 0;
		tstatus->return_value = WEXITSTATUS (status);
	}

	response->header = TGDB_QUIT;
	response->choice.quit.exit_status = tstatus;
	tgdb_types_append_command (command_list, response);
	*tgdb_will_quit = 1;

	return 0;
}


/* }}}*/

/* Getting Data out of TGDB {{{*/
/******************************************************************************/
/**
 * @name Getting Data out of TGDB
 * These functions are for dealing with getting back data from TGDB
 */
/******************************************************************************/

/*@{*/

/**
 * Gets a response from TGDB.
 * This should be called after tgdb_recv_debugger_data
 *
 * \param tgdb
 * An instance of the tgdb library to operate on.
 *
 * @return
 * A valid response if responses still exist.
 * Null if no more responses exist.
 */
struct tgdb_response * Ctgdb::Get_response()
{
	struct tgdb_response *command;

	if (command_list_iterator == NULL)
		return NULL;

	command = (struct tgdb_response *) tgdb_list_get_item (command_list_iterator);

	command_list_iterator = tgdb_list_next (command_list_iterator);

	return command;
}

ITarget* Ctgdb::Get_target()
{
	return m_target;
}
/**
 * This will traverse all of the responses that the context tgdb currently
 * has and will print them. It is currently used for debugging purposes.
 *
 * \param tgdb
 * An instance of the tgdb library to operate on.
 */
void Ctgdb::Traverse_responses()
{
	tgdb_list_foreach(command_list, tgdb_types_print_command);
}
/**
 * This will free all of the memory used by the responses that tgdb returns.
 *
 * \param tgdb
 * An instance of the tgdb library to operate on.
 */
void Ctgdb::Delete_responses()
{
	tgdb_list_free(command_list, tgdb_types_free_command);
}

/* Inferior tty commands {{{*/
/******************************************************************************/
/**
 * @name Inferior tty commands
 * These functinos are used to alter the tty state of the inferior program.
 * These functions currently are not always supported. If the annotate_two
 * subsytem is being used, the tty commands are supported.
 */
/******************************************************************************/

/*@{*/

/**
 * This allocates a new tty and tells the debugger to use it for I/O
 * with the program being debugged.
 *
 * Whatever was left in the old tty is lost, the debugged program starts
 * with a new tty.
 *
 * \param tgdb
 * An instance of the tgdb library to operate on.
 *
 * NOTE
 *  The return value only indicates whether the tty was allocated properly,
 *  not whether the debugger accepted the tty, since this can only be determined 
 *  when the debugger responds, not when the command is given.
 *
 * @return
 * 0 on success or -1 on error
 */
int Ctgdb::Tty_new()
{
	int ret = tgdb_client_open_new_tty (tcc,
			&inferior_stdin,
			&inferior_stdout);

	Process_client_commands();

	return ret;
}
/**
 * Gets the name of file that debugger is using for I/O with the program
 * being debugged.
 * 
 * \param tgdb
 * An instance of the tgdb library to operate on.
 *
 * @return
 * Name of tty or NULL on error.
 */
const char * Ctgdb::Get_tty_name()
{
	return tgdb_client_get_tty_name (tcc);
}

/* Functional commands {{{*/
/******************************************************************************/
/**
 * @name Functional commands
 * These functinos are used to ask the TGDB context to perform a task.
 */
/******************************************************************************/

/*@{*/

/**
 * This sends a console command to the debugger (GDB).
 *
 * \param tgdb
 * An instance of the tgdb library to operate on.
 *
 * \param command
 * The null terminated command to pass to GDB as a console command.
 * 
 * \return
 * Will return as a tgdb request command on success, otherwise NULL.
 */
tgdb_request_ptr Ctgdb::Request_run_console_command(const char *command)
{
	tgdb_request_ptr request_ptr;
	if (!command)
		return NULL;

	request_ptr = (tgdb_request_ptr)
		cgdb_malloc (sizeof (struct tgdb_request));
	if (!request_ptr)
		return NULL;

	request_ptr->header = TGDB_REQUEST_CONSOLE_COMMAND;
	request_ptr->choice.console_command.command = (const char *)
		cgdb_strdup (command);


	return request_ptr;
}
/**
 * Gets a list of source files that make up the program being debugged.
 *
 * This function does not actually do anything but put a command in the 
 * queue to be run when libtgdb is ready. When the libtgdb runs the
 * command to get the inferior's source files, it will return 1 of 2
 * things next time tgdb_recv is called.
 *
 * If the function succeeds the gui will get back TGDB_UPDATE_SOURCE_FILES
 * containing a list of all the source files. Otherwise the gui will get
 * back TGDB_SOURCES_DENIED.
 *
 * \param tgdb
 * An instance of the tgdb library to operate on.
 *
 * \return
 * Will return as a tgdb request command on success, otherwise NULL.
 */
tgdb_request_ptr Ctgdb::Request_inferiors_source_files()
{
	tgdb_request_ptr request_ptr;

	request_ptr = (tgdb_request_ptr)
		cgdb_malloc (sizeof (struct tgdb_request));
	if (!request_ptr)
		return NULL;

	request_ptr->header = TGDB_REQUEST_INFO_SOURCES;

	return request_ptr;
}
/**
 * This gets the absolute path and the relative path from the given file, 
 * FILE. The file parameter should have been returned by 
 * tgdb_request_inferiors_source_files. It can return both relative and 
 * absolute filenames.
 *
 * Basically, if the parameter file is a relative path OR an absolute path, 
 * both the relative path and the absolute path will be returned in the 
 * response.
 *
 * If this functions succeeds TGDB_ABSOLUTE_SOURCE_ACCEPTED will be returned.
 * Otherwise, TGDB_ABSOLUTE_SOURCE_DENIED gets returned.
 *
 * \param tgdb
 * An instance of the tgdb library to operate on.
 *
 * \param file
 * The relative filename to get the absolute path of. If this is passed in as
 * NULL, then this function will return NULL.
 *
 * \return
 * Will return as a tgdb request command on success, otherwise NULL.
 */
tgdb_request_ptr Ctgdb::Request_filename_pair(const char *file)
{
	tgdb_request_ptr request_ptr;

	if (!file)
		return NULL;

	request_ptr = (tgdb_request_ptr)
		cgdb_malloc (sizeof (struct tgdb_request));
	if (!request_ptr)
		return NULL;

	request_ptr->header = TGDB_REQUEST_FILENAME_PAIR;

	if (file) {
		request_ptr->choice.filename_pair.file = (const char *)
			cgdb_strdup (file);
	} else
		request_ptr->choice.filename_pair.file = NULL;


	return request_ptr;
}
/**
 * This will ask the debugger for it's current file and line number.
 * It will return to the caller a tgdb_response with the 
 * response->update_source_files set. This is the same response you 
 * will get when TGDB asynchronously sends the update_file_postition.
 *
 * \param tgdb
 * An instance of the tgdb library to operate on.
 * 
 * \param on_starup
 * This variable can be set to 1 if the front end wants to probe GDB
 * for the initial file and location of the program being debugged.
 * However, each initial time after that, this variable should be 
 * set to 0.
 *
 * \return
 * Will return as a tgdb request command on success, otherwise NULL.
 */
tgdb_request_ptr Ctgdb::Request_current_location(int on_startup)
{
	tgdb_request_ptr request_ptr;

	request_ptr = (tgdb_request_ptr)
		cgdb_malloc (sizeof (struct tgdb_request));
	if (!request_ptr)
		return NULL;

	request_ptr->header = TGDB_REQUEST_CURRENT_LOCATION;
	request_ptr->choice.current_location.on_startup = on_startup;

	return request_ptr;
}
/**
 * This tells libtgdb to run a command through the debugger.
 *
 * \param tgdb
 * An instance of the tgdb library to operate on.
 *
 * \param c
 * This is the command that libtgdb should run through the debugger.
 *
 * @return
 * Will return as a tgdb request command on success, otherwise NULL.
 */
tgdb_request_ptr Ctgdb::Request_run_debugger_command(enum tgdb_command_type c)
{
	tgdb_request_ptr request_ptr;

	request_ptr = (tgdb_request_ptr)
		cgdb_malloc (sizeof (struct tgdb_request));
	if (!request_ptr)
		return NULL;

	request_ptr->header = TGDB_REQUEST_DEBUGGER_COMMAND;
	request_ptr->choice.debugger_command.c = c;

	return request_ptr;
}
/**
 * Modify's a breakpoint.
 *
 * \param tgdb
 * An instance of the tgdb library to operate on.
 *
 * \param file
 * The file to set the breakpoint in.
 *
 * \param line
 * The line in FILE to set the breakpoint in.
 *
 * \param b
 * Determines what the user wants to do with the breakpoint.
 *
 * @return
 * Will return as a tgdb request command on success, otherwise NULL.
 */
tgdb_request_ptr Ctgdb::Request_modify_breakpoint(const char *file,
		int line, 
		enum tgdb_breakpoint_action b)
{
	tgdb_request_ptr request_ptr;
	request_ptr = (tgdb_request_ptr)
		cgdb_malloc (sizeof (struct tgdb_request));
	if (!request_ptr)
		return NULL;

	request_ptr->header = TGDB_REQUEST_MODIFY_BREAKPOINT;
	request_ptr->choice.modify_breakpoint.file = (const char *)
		cgdb_strdup (file);
	request_ptr->choice.modify_breakpoint.line = line;
	request_ptr->choice.modify_breakpoint.b = b;

	return request_ptr;
}
/**
 * Used to get all of the possible tab completion options for LINE.
 *
 * \param tgdb
 * An instance of the tgdb library to operate on.
 *
 * \param line
 * The line to tab complete.
 *
 * \return
 * Will return as a tgdb request command on success, otherwise NULL.
 */
tgdb_request_ptr Ctgdb::Request_complete(const char *line)
{
	tgdb_request_ptr request_ptr;

	request_ptr = (tgdb_request_ptr)
		cgdb_malloc (sizeof (struct tgdb_request));
	if (!request_ptr)
		return NULL;

	request_ptr->header = TGDB_REQUEST_COMPLETE;
	request_ptr->choice.complete.line = (const char *)
		cgdb_strdup (line);

	return request_ptr;
}

/* TGDB Queue commands {{{*/
/******************************************************************************/
/**
 * @name Queuing of TGDB commands
 * These functinos are used to allow clients to queue multiple commands for 
 * TGDB to be able to run.
 */
/******************************************************************************/

/**
 * Have TGDB append a command to it's list of commands it needs to run.
 * 
 * \param tgdb
 * An instance of the tgdb library to operate on.
 * 
 * \param request
 * The requested command to have TGDB process.
 *
 * \return
 * 0 on success or -1 on error
 */
int Ctgdb::Queue_append(tgdb_request_ptr request)
{
	if (!request)
		return -1;

	queue_append(gdb_client_request_queue, request);

	return 0;
}
/**
 * Get a tgdb_request command back from TGDB.
 *
 * \param tgdb
 * An instance of the tgdb library to operate on.
 *
 * \return
 * The requested command at the top of the stack, or NULL on error.
 * Popping a command when the queue is empty is also considered an error,
 * and NULL will be returned.
 */
tgdb_request_ptr Ctgdb::Queue_pop()
{
	tgdb_request_ptr item;

	item = (tgdb_request_ptr) queue_pop(gdb_client_request_queue);

	return item;
}
/**
 * Get's the number of items that are in the queue for TGDB to run.
 *
 * \param tgdb
 * An instance of the tgdb library to operate on.
 *
 * \size
 * The number of items in the list.
 *
 * \return
 * 0 on success or -1 on error
 */
int Ctgdb::Queue_size (int *size)
{
	if (!size)
		return -1;

	*size = queue_size (gdb_client_request_queue);

	return 0;
}
/* }}}*/

/* Signal Handling Support {{{*/
/******************************************************************************/
/**
 * @name Signal Handling Support
 * These functinos are used to notify TGDB of signal recieved.
 */
/******************************************************************************/

/*@{*/

/**
 * The front end can use this function to notify libtgdb that an
 * asynchronous event has occurred. If signal SIGNUM is relavant
 * to libtgdb, the appropriate processing will be done.
 * Currently, TGDB only handles SIGINT,SIGTERM and SIGQUIT.
 *
 * libtgdb will remove all elements from it's queue when a SIGINT
 * is received.
 *
 * \param tgdb
 * An instance of the tgdb library to operate on.
 *
 * \param signum
 * The signal number SIGNUM that has occured.
 *
 * @return
 * 0 on success or -1 on error
 */
int Ctgdb::Signal_notification (int signum)
{
	struct termios t;
	cc_t *sig_char = NULL;

	tcgetattr (debugger_stdin, &t);

	if (signum == SIGINT)
	{				/* ^c */
		control_c = 1;
		sig_char = &t.c_cc[VINTR];
		write (debugger_stdin, sig_char, 1);
	}
	else if (signum == SIGQUIT)
	{				/* ^\ */
		sig_char = &t.c_cc[VQUIT];
		write (debugger_stdin, sig_char, 1);
	}
	else if (signum == SIGCHLD)
	{
		has_sigchld_recv = 1;
	}

	return 0;
}


/* Config Options {{{*/
/******************************************************************************/
/**
 * @name TGDB Config Options
 * These functinos are used to change the state TGDB works. TGDB can currently
 * only be configured through this interface.
 */
/******************************************************************************/

/*@{*/

/**
 * This sets the verbosity of the GUI's commands.
 * If the value is set to 0, the GUI's commands will not be shown.
 * If the value is set to 1, the GUI's commands will be shown.
 * The default value for TGDB is to be off.
 *
 * \param tgdb
 * An instance of the tgdb library to operate on.
 *
 * \param value
 * 0 to not show GUI commands, 1 to show them, otherwise nothing is done.
 * You would use a value other than 0 or 1 just to query if the option is set.
 *
 * @return
 * 1 if option is set, otherwise 0
 */
int Ctgdb::Set_verbose_gui_command_output (int value)
{
	if ((value == 0) || (value == 1))
		show_gui_commands = value;

	if (show_gui_commands == 1)
		return 1;

	return 0;
}

/**
 * This will make TGDB handle error's in a verbose mode.
 * The basically mean's that when TGDB find's an error, the message is
 * printed to stdout/stderr. Normally this is not acceptable because TGDB can
 * simple not print when any front end is using it. Imparticular, TGDB can
 * not print when a curses based front end is using it.
 *
 * \param tgdb
 * An instance of the tgdb library to operate on.
 *
 * \param value
 * if -1, query to see if the option is set.
 * If 0, the option will be turned off.
 * If 1, the option will be turned on.
 *
 * @return
 * 1 if option is set, otherwise 0
 */
int Ctgdb::Set_verbose_error_handling (int value)
{
	if (value == -1)
		return logger_is_recording (m_logger);

	if (value == 1 || value == 0)
		logger_set_record (m_logger, value);

	if (value == 1)
		logger_set_fd (m_logger, stderr);

	return logger_is_recording (m_logger);
}

